#pragma once

#include <iostream>
#include <unistd.h>
#include <string>
#include <vector>
#include <queue>
#include <functional>
#include "Thread.hpp"
#include "Log.hpp"
#include "LockGuard.hpp"

using namespace ThreadMoudle;
using namespace log_ns;

static const int gdefaultnum = 10;

void test()
{
    while (true)
    {
        std::cout << "hello world" << std::endl;
        sleep(1);
    }
}

template <typename T>
class ThreadPool
{
private:
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void UnlockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void Wakeup()
    {
        pthread_cond_signal(&_cond);
    }
    void WakeupAll()
    {
        pthread_cond_broadcast(&_cond);
    }
    void Sleep()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }
    bool IsEmpty()
    {
        return _task_queue.empty();
    }
    void HandlerTask(const std::string &name) // this
    {
        while (true)
        {
            // 取任务
            LockQueue();
            while (IsEmpty() && _isrunning)
            {
                _sleep_thread_num++;
                LOG(INFO, "%s thread sleep begin!\n", name.c_str());
                Sleep();
                LOG(INFO, "%s thread wakeup!\n", name.c_str());
                _sleep_thread_num--;
            }
            // 判定一种情况
            if (IsEmpty() && !_isrunning)
            {
                UnlockQueue();
                LOG(INFO, "%s thread quit\n", name.c_str());
                break;
            }

            // 有任务
            T t = _task_queue.front();
            _task_queue.pop();
            UnlockQueue();

            // 处理任务
            t(); // 处理任务，此处不用/不能在临界区中处理
            // std::cout << name << ": " << t.result() << std::endl;
            // LOG(DEBUG, "hander task done, task is : %s\n", t.result().c_str());
        }
    }
    void Init()
    {
        func_t func = std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1);
        for (int i = 0; i < _thread_num; i++)
        {
            std::string threadname = "thread-" + std::to_string(i + 1);
            _threads.emplace_back(threadname, func);
            LOG(DEBUG, "construct thread %s done, init success\n", threadname.c_str());
        }
    }
    void Start()
    {
        _isrunning = true;
        for (auto &thread : _threads)
        {
            LOG(DEBUG, "start thread %s done.\n", thread.Name().c_str());
            thread.Start();
        }
    }
    ThreadPool(int thread_num = gdefaultnum)
        : _thread_num(thread_num), _isrunning(false), _sleep_thread_num(0)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }
    ThreadPool(const ThreadPool<T> &) = delete;
    void operator=(const ThreadPool<T> &) = delete;

public:
    void Stop()
    {
        LockQueue();
        _isrunning = false;
        WakeupAll();
        UnlockQueue();
        LOG(INFO, "Thread Pool Stop Success!\n");
    }

    // 如果是多线程获取单例呢？
    static ThreadPool<T> *GetInstance()
    {
        if (_tp == nullptr)
        {
            LockGuard lockguard(&_sig_mutex);
            if (_tp == nullptr)
            {
                LOG(INFO, "create threadpool\n");
                // thread-1 thread-2 thread-3....
                _tp = new ThreadPool<T>();
                _tp->Init();
                _tp->Start();
            }
            else
            {
                LOG(INFO, "get threadpool\n");
            }
        }
        return _tp;
    }

    void Equeue(const T &in)
    {
        LockQueue();
        if (_isrunning)
        {
            _task_queue.push(in);
            if (_sleep_thread_num > 0)
                Wakeup();
        }
        UnlockQueue();
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    int _thread_num;
    std::vector<Thread> _threads;
    std::queue<T> _task_queue;
    bool _isrunning;

    int _sleep_thread_num;

    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    // 单例模式
    // volatile static ThreadPool<T> *_tp;
    static ThreadPool<T> *_tp;
    static pthread_mutex_t _sig_mutex;
};

template <typename T>
ThreadPool<T> *ThreadPool<T>::_tp = nullptr;
template <typename T>
pthread_mutex_t ThreadPool<T>::_sig_mutex = PTHREAD_MUTEX_INITIALIZER;


// 这段代码实现了一个 线程池 模式，提供了多线程处理任务的能力，能够管理多个线程执行任务，并且通过线程池单例模式（Singleton）来确保只会创建一个线程池实例。
// 类定义：ThreadPool<T>
// ThreadPool 类是一个模板类，能够处理类型为 T 的任务，其中 T 应该是一个可以调用的对象（即有 operator() 定义的对象）。ThreadPool 负责管理一组线程，这些线程会从任务队列中取出任务并执行。
// 成员变量：
// 线程池大小：_thread_num 表示线程池中线程的数量。
// 线程队列：_threads 用来存储所有创建的线程。
// 任务队列：_task_queue 是一个 std::queue，存储待处理的任务。
// 运行状态：_isrunning 标志线程池是否正在运行。
// 空闲线程数：_sleep_thread_num 表示当前空闲的线程数量。
// 同步机制：
// _mutex：用于保护任务队列的互斥锁。
// _cond：用于线程同步的条件变量，确保线程池在没有任务时可以进入等待状态。
// 单例模式：
// _tp：一个静态指针，用于存储线程池的唯一实例。
// _sig_mutex：一个静态互斥锁，用于控制对 _tp 的访问，确保线程池的单例实现是线程安全的。
// 成员函数：
// (1) 同步操作：
// LockQueue() 和 UnlockQueue()：这些是保护任务队列的互斥锁方法，确保在访问任务队列时线程是同步的，避免并发冲突。
// Wakeup() 和 WakeupAll()：分别是唤醒一个或所有线程的函数。当有任务加入时，如果某些线程在等待任务，这些函数可以用来通知线程继续工作。
// Sleep()：如果任务队列为空，线程会调用这个函数进入等待状态，直到有新的任务被加入到队列中。
// IsEmpty()：检查任务队列是否为空。
// (2) 任务处理：
// HandlerTask()：这是线程执行的主要任务。每个线程会不断地从任务队列中获取任务并执行，直到线程池被停止。
// 线程首先会尝试从任务队列中取出任务。
// 如果队列为空且线程池仍然在运行，线程将会休眠，直到有新任务到来。
// 如果线程池已停止并且队列为空，线程将退出。
// 如果队列非空，线程会执行任务。
// (3) 初始化和启动：
// Init()：为线程池中的每个线程创建一个 Thread 对象，并绑定任务处理函数 HandlerTask()，然后将线程添加到 _threads 向量中。
// Start()：启动所有线程。
// (4) 停止：
// Stop()：停止线程池，首先设置 _isrunning = false，然后唤醒所有处于等待状态的线程。
// (5) 单例实现：
// GetInstance()：这是一个线程安全的单例实现，使用双重检查锁定（Double-Checked Locking）来确保线程池实例 _tp 只会被创建一次。_sig_mutex 用于同步对 _tp 的访问。
// (6) 任务队列：
// Equeue()：将任务 in 添加到任务队列中。任务加入后，如果有空闲线程，某些线程会被唤醒来处理这些任务。
// (7) 析构函数：
// pthread_mutex_destroy(&_mutex) 和 pthread_cond_destroy(&_cond) 用于销毁互斥锁和条件变量，释放相关资源。
// 线程池的工作流程：
// 初始化和启动线程池：
// 通过 ThreadPool<T>::GetInstance() 获取线程池的唯一实例（如果还没有创建）。
// 调用 ThreadPool::Start() 启动线程池中的所有线程，每个线程执行 HandlerTask() 函数。
// 任务处理：
// 任务通过 ThreadPool::Equeue() 被加入到任务队列 _task_queue 中。
// 线程在 HandlerTask() 中从队列中取任务并执行。
// 线程阻塞与唤醒：
// 如果队列为空，线程会调用 Sleep() 进入等待状态，直到有新任务被添加。
// 当任务被加入队列时，如果有空闲线程，它们会被唤醒执行任务。
// 停止线程池：
// 调用 ThreadPool::Stop() 停止线程池，设置 _isrunning = false，并唤醒所有等待中的线程。每个线程在执行完当前任务后退出。
// 单例模式的线程安全性分析：
// ThreadPool<T>::GetInstance() 中使用了双重检查锁定（Double-Checked Locking）来实现线程安全的单例模式：
// 第一次检查 _tp == nullptr 是为了减少锁的竞争。
// 第二次检查 _tp == nullptr 是为了确保在锁定后 _tp 仍然没有被创建（避免其他线程已经创建了 ThreadPool 实例）。
// LockGuard 用于确保在操作 _tp 时，访问是线程安全的。